package blog

import (
	"context"
	"strconv"

	"github.com/gin-gonic/gin"
)

const (
	AppName = "blogs"
)

// 接口的定义很关键, 他站在使用的角度来定义,
// 接口是开放给上层业务使用, 要保证兼容性
type Service interface {
	// 创建文章
	CreateBlog(context.Context, *CreateBlogRequest) (*Blog, error)
	// 文章列表查询, 不会查询出文章的内容, 支持分页，支持关键字搜索, 支持状态过滤
	// 管理员: 可以查看所有所有状态的文章
	// 访客: 查看已经发布的文章
	// QueryBlog(context.Context, PageSize, PageNumber, keywords, Status)
	// 需要加一个过滤条件? 根据文章的作者进行过滤
	// 1. QueryBlog(..., author ), 破坏了接口
	// 2. 单独定义一个接口( 接口非常多，功能不清晰，不聚焦, 对于使用方不友好)
	// 必须定义为一个结构体, 通过结构体来保证兼容性
	QueryBlog(context.Context, *QueryBlogRequest) (*BlogSet, error)
	// 查询详情, 查看某一篇具体的文章, 需要查看文章内容
	DescribeBlog(context.Context, *DescribeBlogRequest) (*Blog, error)
	// 修改
	UpdateBlog(context.Context, *UpdateBlogRequest) (*Blog, error)
	// 删除, 同时把删除的对象也返回出去了? 这个为了兼容性
	// 比如 你的审计系统 需要知道用户到底删除了那个对象, 这是返回删除对象信息就很有 用
	// 比如，你要恢复删除的对象
	// 比如 事件触发: 事件的接收方需要知道被删除对象的信息 DeleteBlogEvent {}
	DeleteBlog(context.Context, *DeleteBlogRequest) (*Blog, error)
}

func NewQueryBlogRequest() *QueryBlogRequest {
	return &QueryBlogRequest{
		PageSize:   20,
		PageNumber: 1,
	}
}

func NewQueryBlogRequestFromGin(c *gin.Context) (*QueryBlogRequest, error) {
	req := NewQueryBlogRequest()
	// 参数解析逻辑
	// ?a=b&c=d
	// c.Request.URL.Query()
	ps := c.Query("page_size")
	pn := c.Query("page_number")
	if ps != "" {
		req.PageSize, _ = strconv.Atoi(ps)
	}
	if pn != "" {
		req.PageNumber, _ = strconv.Atoi(pn)
	}
	req.Author = c.Query("author")
	req.Keywords = c.Query("keywords")
	statusStr := c.Query("status")
	if statusStr != "" {
		status, err := ParseStatusFromString(statusStr)
		if err != nil {
			return nil, err
		}
		req.Status = status
	}

	return req, nil
}

type QueryBlogRequest struct {
	// 分页的大小
	PageSize int
	// 页码
	PageNumber int
	// 关键字参数, 用于模糊搜索, 只支持模糊搜索文章名称
	// 怎么实现: SQL: Where (title LIKE % OR summary LIKE %)
	Keywords string
	// 支持状态过滤, 可以不过来状态, 怎么表述用户没有传递给参数
	// Status Status ? 不能? Status 有默认值：0, 代表的Draft
	Status *Status
	// 根据作者名称来进行过滤
	Author string
}

func (req *QueryBlogRequest) Offset() int64 {
	// page 3页   一页20个, offset 2*20, limit 20
	return int64(req.PageNumber-1) * int64(req.PageSize)
}

func NewDescribeBlogRequest(id int) *DescribeBlogRequest {
	return &DescribeBlogRequest{
		Id: id,
	}
}

type DescribeBlogRequest struct {
	// 文章的ID
	Id int
}

func NewPutUpdate(id int, req *CreateBlogRequest) *UpdateBlogRequest {
	return NewUpdateBlogRequest(PUT, id, req)
}

func NewPatchUpdate(id int, req *CreateBlogRequest) *UpdateBlogRequest {
	return NewUpdateBlogRequest(PATCH, id, req)
}

func NewUpdateBlogRequest(mode UpdateMode, id int, req *CreateBlogRequest) *UpdateBlogRequest {
	return &UpdateBlogRequest{
		UpdateMode:        mode,
		Id:                id,
		CreateBlogRequest: req,
	}
}

type UpdateBlogRequest struct {
	// 文章的ID
	Id int `json:"id"`
	// 更新模式
	UpdateMode UpdateMode `json:"update_mode"`
	// 思维: 保证对象复用, 这样对象有修改的时候，才会跟随
	*CreateBlogRequest
}

func NewDeleteBlogRequest(id int) *DeleteBlogRequest {
	return &DeleteBlogRequest{
		Id: id,
	}
}

type DeleteBlogRequest struct {
	// 文章的ID
	Id int `json:"id"`
}
